import {
  ArgumentsHost,
  BadRequestException,
  Catch,
  ExceptionFilter,
  HttpException,
  NotFoundException,
  UnauthorizedException,
} from '@nestjs/common';
import { Response } from 'express';
import { BusinessException } from '../../types/exception/business.exception';
import { ApiReturnType } from '../../types/interface/api.interface';
import { HTTP_CODE } from '../../types/enum/http-code.enum';
import { ERR_MSG } from '../../types/errcode';

@Catch()
export class CustomExceptionFilter implements ExceptionFilter {
  catch(exception: Error, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const body: ApiReturnType<string | object> =
      this.createBaseResponse(exception);

    if (exception instanceof UnauthorizedException) {
      return this.handleJwtError(response, body);
    }

    if (exception instanceof BadRequestException) {
      return this.handleParamValidationError(response, exception, body);
    }

    if (exception instanceof NotFoundException) {
      return this.handleRouteNotFoundError(response, exception, body);
    }

    if (exception instanceof BusinessException) {
      return this.handleBusinessError(response, exception, body);
    }

    if (exception instanceof HttpException) {
      return this.handleHttpException(response, exception, body);
    }

    // 通用错误处理
    return this.handleUnknownError(response, body);
  }

  private createBaseResponse(exception: Error): ApiReturnType<string | object> {
    return {
      success: false,
      data: {},
      code: '',
      msg: { desc: exception.name, detail: exception.message },
      timestamp: Date.now(),
    };
  }

  private handleJwtError(response: Response, body: ApiReturnType<any>): void {
    const errObj = ERR_MSG.AUTH_JWT_ERROR;
    body.code = errObj.code;
    body.msg = { desc: errObj.msg };
    body.data = {};
    response.status(HTTP_CODE.JWT_ERROR).json(body);
  }

  private handleParamValidationError(
    response: Response,
    exception: BadRequestException,
    body: ApiReturnType<any>,
  ): void {
    const errObj = ERR_MSG.PARAMS_NOT_MATCH;
    body.code = errObj.code;
    body.msg = { desc: errObj.msg, detail: exception.getResponse() };
    response.status(HTTP_CODE.DTO_NOT_MATCH).json(body);
  }

  private handleRouteNotFoundError(
    response: Response,
    exception: NotFoundException,
    body: ApiReturnType<any>,
  ): void {
    const errObj = ERR_MSG.ROUTE_NOT_FOUND;
    body.code = errObj.code;
    body.msg = { desc: errObj.msg, detail: exception.getResponse() };
    response.status(HTTP_CODE.ROUTE_METHOD_WRONG).json(body);
  }

  private handleBusinessError(
    response: Response,
    exception: BusinessException,
    body: ApiReturnType<any>,
  ): void {
    body.code = exception.getCode;
    body.data = {
      processMsg: exception.getProcessMsg,
      processUrl: exception.getProcessUrl,
    };
    body.msg = { desc: exception.getMsg };
    response.json(body); // 默认 200
  }

  private handleHttpException(
    response: Response,
    exception: HttpException,
    body: ApiReturnType<any>,
  ): void {
    response.status(exception.getStatus()).json(body);
  }

  private handleUnknownError(
    response: Response,
    body: ApiReturnType<any>,
  ): void {
    body.code = '';
    response.status(HTTP_CODE.SERVER_ERROR).json(body);
  }
}
